import csv
import os
import setup_dirs
from lxml import etree
from util.CustomConfigParser import getConfigFromConfigfile


class ScrapeConfigManager:
    config_dir = setup_dirs.configs
    data_dir = setup_dirs.data

    def __init__(self, logger=None):
        """Class for managing article configuration files."""
        self.configs = set()
        self.sourceTable = dict()
        self.logger = logger
        self.index_configs()
        self.build_sourceTable()

    def check_cfile(self, cname):
        validity = True
        response = ''
        config = None
        if (cname == 'template') or ('_OFFLINE' in cname):
            validity = False
        elif cname not in self.configs:
            validity = False
            response = 'No configs found by this name: \'' + cname + '\''
        else:
            config = self.get_config(cname)
            if config is None:
                validity = False
                response = 'Config file \'' + cname + '.cfg\' appears to be incorrectly formatted'
            elif not self.are_xpaths_correct(config):
                validity = False
                response = 'Config file \'' + cname + '.cfg\' contains a syntactically incorrect xpath'
            elif config['source_Id_idmi']['sourceid'] == '':
                validity = False
                response = 'Config file \'' + cname + '.cfg\' does not specify a source_Id'
        return validity, response, config

    def check_config_format(self, config, cname):
        """Check if configuration file is valid."""
        format_valid = True

        if not config:
            return False

        if not all(
                x in config.keys() for x in ['source_Id_idmi',
                                             'header',
                                             'Demand_info',
                                             'index_pages_urls',
                                             'Index_Page_Xpath',
                                             'Index_Page_Add_Info',
                                             'Detail_Page_Xpath',
                                             'Detail_Page_Img']):
            self.logger.info('ERROR : Missing section')
            return False

        format_valid = format_valid and 'domain' in config['header'] \
                       and 'title' in config['Detail_Page_Xpath'] \
                       and 'text' in config['Detail_Page_Xpath']

        return format_valid

    def are_xpaths_correct(self, config):
        for k in config:
            if k == 'Detail_Page_Xpath':
                for i in config[k]:
                    if isinstance(config[k][i], list):
                        for item in config[k][i]:
                            if not self.validateXpath(item):
                                return False
                    else:
                        if not self.validateXpath(config[k][i]):
                            return False
        return True

    def validateXpath(self, path):
        cpath = path
        if ';' in path:
            cpath = path.partition(';')[0]
        if "\"" in cpath:
            if self.logger is not None:
                self.logger.error("\"s are not permitted inside xpath. Please use single quotation marks instead.")
            return False
        try:
            etree.XPath(cpath)
            return True
        except etree.XPathSyntaxError:
            if self.logger is not None:
                self.logger.error("The expression " + cpath + " is no valid xpath")
            return False

    def get_configs_by_sourceId(self, sourceId):
        if sourceId in self.sourceTable:
            return self.sourceTable[sourceId]
        else:
            return None

    def get_config(self, cname):
        config = getConfigFromConfigfile(self.get_filepath(cname))
        return config
        # Postprocessing of index urls. Make sure index urls is a list.
        # index_pages = config['index_pages_urls']['urls']
        # if isinstance(index_pages, str):
        #     self.logger.error('Make Sure the ' + cname + '.cfg file is correct')
        #     return None
        #
        # if self.check_config_format(config, cname):
        #     return config
        #
        # else:
        #     return None

    def build_sourceTable(self):
        for cname in self.configs:
            validity, response, config = self.check_cfile(cname)
            if validity:
                self.sourceTable.setdefault(config['source_Id_idmi']['sourceid'], []).append(cname)
            elif (response != '') and (self.logger is not None):
                self.logger.error(response)

    def index_configs(self):
        """Check files in config folder and index config by name."""

        files = os.listdir(ScrapeConfigManager.config_dir)

        self.configs.clear()

        for file in files:
            split = os.path.splitext(file)
            if '_OFFLINE' not in split[0]:
                self.configs.add(split[0])

    def get_configs(self):
        return self.configs - {'template'}

    def create_overview(self):
        files = os.listdir(ScrapeConfigManager.config_dir)
        nameslist = set()

        for file in files:
            split = os.path.splitext(file)
            if 'template' not in split[0] and 'overview' not in split[0]:
                nameslist.add(split[0])

        with open(self.data_dir + '/config_overview_sheet.csv', 'w+') as csvfile:
            filewriter = csv.writer(csvfile, delimiter=';')
            filewriter.writerow(['config_file_name', 'sourceid',
                                 'source_language', 'tarnslate_language',
                                 'Index_Page_Urls',
                                 'comments', 'Data_Preprocess_method'])
            # one blank line for improved readability
            filewriter.writerow([])
            for cname in nameslist:
                config = self.get_config(cname)
                if isinstance(config['Data_preprocess_method']['translate_language'], list):
                    config['Data_preprocess_method']['translate_language'] = [' ']
                else:
                    self.logger.error(cname + '.cfg file is incorrect in translate language setting')

                if not isinstance(config['index_pages_urls']['urls'], list):
                    self.logger.error(cname + '.cfg file is incorrect in index page Urls, need one list')

                try:
                    filewriter.writerow([cname + '.cfg',  # config_file_name
                                         config['source_Id_idmi']['sourceid'],  # sourceid
                                         config['Data_info']['source_language'],  # source_language
                                         ' | '.join(config['Data_preprocess_method']['translate_language']),  # translate_language
                                         config['index_pages_urls']['urls'],  # Index_Page_Urls
                                         config['Data_preprocess_method']['comments'],  # comments
                                         config['Data_preprocess_method']['method_tag']  # Data preprocessing method tag
                                         ])
                except KeyError:
                    self.logger.warn('config for ' + cname + ' appears to have a missing or'
                                                             ' incorrect \'metadata\' - section')

    @staticmethod
    def get_filepath(sourceId):
        return ScrapeConfigManager.config_dir + '/' + sourceId + '.cfg'
